﻿namespace TestProject
{
    using System;
    using System.Collections.Specialized;
    using System.Diagnostics;
    using System.IO;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Swiss;

    /// <summary>
    /// Summary description for UnitTest1
    /// </summary>
    [TestClass]
    public class Sparse_Tests
    {
        public Sparse_Tests()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region SparseMatrix

        [Owner("wvd_vegt"), Description("Basics"), TestMethod]
        public void TestCreateMatrix()
        {
            const Int32 Size = 5;
            Sparse<Double> s = new Sparse<Double>(Size, Size, Size, "Nop Comment");

            DumpMatrixes<Double>(s);
        }

        [Owner("wvd_vegt"), Description("Basics"), TestMethod]
        public void TestDiagonalMatrix()
        {
            Sparse<Double> s = DemoMatrix5();

            DumpMatrixes<Double>(s);
        }

        [Owner("wvd_vegt"), Description("Basics"), TestMethod]
        public void TestExampleMatrix()
        {
            Sparse<Double> s = DemoMatrix1();

            DumpMatrixes<Double>(s);
        }

        [Owner("wvd_vegt"), Description("Clear"), TestMethod]
        public void TestClearMatrix()
        {
            Sparse<Double> s = DemoMatrix1();

            s.Clear();

            DumpMatrixes<Double>(s);
        }

        [Owner("wvd_vegt"), Description("Basics"), TestMethod]
        public void TestElementMatrix()
        {
            Sparse<Double> s = DemoMatrix1();

            Console.WriteLine("Element[3,3] = {0}", s[3, 3]);

            Debug.Assert(s[0, 0] == 11, "Mismatch [0,0]");
            Debug.Assert(s[0, 3] == 14, "Mismatch [0,3]");
            Debug.Assert(s[1, 1] == 22, "Mismatch [1,1]");
            Debug.Assert(s[1, 4] == 25, "Mismatch [1,4]");
            Debug.Assert(s[2, 2] == 33, "Mismatch [2,2]");
            Debug.Assert(s[3, 0] == 41, "Mismatch [3,0]");
            Debug.Assert(s[3, 3] == 44, "Mismatch [3,3]");
            Debug.Assert(s[3, 4] == 45, "Mismatch [3,4]");
            Debug.Assert(s[4, 0] == 51, "Mismatch [4,0]");
            Debug.Assert(s[4, 3] == 54, "Mismatch [4,3]");
            Debug.Assert(s[4, 4] == 55, "Mismatch [4,4]");

            s[3, 3] = 99.0;

            Debug.Assert(s[3, 3] == 99, "Mismatch [3,3]");

            DumpMatrixes<Double>(s);
        }

        [Owner("wvd_vegt"), Description("Basics"), TestMethod]
        public void TestMissingRowMatrix()
        {
            Sparse<Double> s = DemoMatrix2();

            DumpMatrixes<Double>(s);
        }

        [Owner("wvd_vegt"), Description("Basics"), TestMethod]
        public void TestCopyMatrix()
        {
            Sparse<Double> s = DemoMatrix2();

            DumpMatrixes<Double>(s);

            Sparse<Double> t = new Sparse<Double>(s);

            DumpMatrixes<Double>(t);
        }

        [Owner("wvd_vegt"), Description("Compress"), TestMethod]
        public void TestCompressMatrix()
        {
            //{
            //    Sparse<Double> s = DemoMatrix3();

            //    DumpMatrixes<Double>(s);
            //    DumpInternals<Double>(s);

            //    s.CopyCompress();

            //    DumpMatrixes<Double>(s);
            //    DumpInternals<Double>(s);
            //}

            {
                Sparse<Double> s = DemoMatrix3();

                s.Compress();

                DumpMatrixes<Double>(s);
                DumpInternals<Double>(s);
            }

            {
                Sparse<Double> s = DemoMatrix3();

                s[1, 1] = 0.0;
                s[1, 4] = 0.0;

                s.Compress();

                DumpMatrixes<Double>(s);
                DumpInternals<Double>(s);
            }

            {
                //Illegal Case (Does not give an Error but outcome is not correct).
                Sparse<Double> s = DemoMatrix3();
                foreach (Sparse<Double>.SparseElement se in s)
                {
                    s[se.Row, se.Column] = 0.0;
                };

                s.Compress();

                DumpMatrixes<Double>(s);
                DumpInternals<Double>(s);
            }
        }

        [Owner("wvd_vegt"), Description("Determinant"), TestMethod]
        public void TestDeterminantMatrix()
        {
            Sparse<Double> s = DemoMatrix4();

            DumpMatrixes<Double>(s);

            Console.WriteLine();
            Console.WriteLine("Determinant: {0}", s.Determinant());
            Console.WriteLine();
        }

        [Owner("wvd_vegt"), Description("Invert"), TestMethod]
        public void TestInvertMatrix()
        {
            {
                Sparse<Int32> s = DemoMatrix6();

                DumpMatrixes<Int32>(s);

                s.Invert();

                DumpMatrixes<Int32>(s);
            }

            {
                Sparse<Double> s = DemoMatrix1();

                DumpMatrixes<Double>(s);

                s.Invert();

                DumpMatrixes<Double>(s);
            }
        }

        [Owner("wvd_vegt"), Description("IEnumerator"), TestMethod]
        public void TestEnumMatrix()
        {
            {
                Int32 ndx;

                Sparse<Double> s = DemoMatrix1();

                ndx = 1;
                foreach (Sparse<Double>.SparseElement se in s)
                {
                    Console.WriteLine("Element {0:00}: R{1:00}C{2:00} = {3}", ndx++, se.Row, se.Column, se.Value.ToString());
                }

                DumpMatrixes<Double>(s);
            }

            {
                Sparse<Int32> s = DemoMatrix7();

                Int32 ndx = 1;
                foreach (Sparse<Int32>.SparseElement se in s)
                {
                    Console.WriteLine("Element {0:00}: R{1:00}C{2:00} = {3}", ndx++, se.Row, se.Column, se.Value.ToString());
                }

                DumpMatrixes<Int32>(s);
            }
        }

        [Owner("wvd_vegt"), Description("Transpose"), TestMethod]
        public void TestTransposeMatrix()
        {
            Sparse<Int32> s = DemoMatrix7();

            DumpMatrixes<Int32>(s);
            DumpInternals<Int32>(s);

            s.Transpose();
            
            DumpMatrixes<Int32>(s);
            DumpInternals<Int32>(s);
        }

        [Owner("wvd_vegt"), Description("SaveHarwellBoeing"), TestMethod]
        public void TestSaveHBMatrix()
        {
            {
                Sparse<Int32> s = DemoMatrix7();

                String FileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "HBInt32Matrix.hb");

                Console.WriteLine("Saved as: " + FileName);
                s.SaveHarwellBoeing(FileName);

                s.Transpose();

                DumpMatrixes<Int32>(s);
                DumpInternals<Int32>(s);
            }

            {
                Sparse<Double> s = DemoMatrix1();

                String FileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "HBDoubleMatrix.hb");

                Console.WriteLine("Saved as: " + FileName);
                s.SaveHarwellBoeing(FileName);

                s.Transpose();

                DumpMatrixes<Double>(s);
                DumpInternals<Double>(s);
            }
        }

        [Owner("wvd_vegt"), Description("SaveMatrixMarket"), TestMethod]
        public void TestSaveMMMatrix()
        {
            {
                Sparse<Int32> s = DemoMatrix7();

                String FileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "MMInt32Matrix.mm");

                Console.WriteLine("Saved as: " + FileName);
                s.SaveMatrixMarket(FileName);

                DumpMatrixes<Int32>(s);
                DumpInternals<Int32>(s);
            }
        }

        [Owner("wvd_vegt"), Description("SaveExcel"), TestMethod]
        public void TestSaveExcelMatrix()
        {
            {
                Sparse<Int32> s = DemoMatrix7();

                String FileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "ExcelInt32Matrix.csv");

                StringCollection rows = new StringCollection();
                rows.Add("Test");
                rows.Add("Te;st");
                rows.Add("Te\"st");
                rows.Add("Te;\"st");

                StringCollection cols = new StringCollection();
                cols.Add("Test");
                cols.Add("Test");
                cols.Add("Test");

                Console.WriteLine("Saved as: " + FileName);
                s.SaveExcel(FileName, rows, cols);

                DumpMatrixes<Int32>(s);
                DumpInternals<Int32>(s);


            }
        }

        [Owner("wvd_vegt"), Description("Cofactor"), TestMethod]
        public void TestCofactorMatrix()
        {
            {
                Sparse<Double> s = DemoMatrix4();

                DumpMatrixes<Double>(s);

                s.Cofactor();

                DumpMatrixes<Double>(s);
                DumpInternals<Double>(s);
            }
        }

        [Owner("wvd_vegt"), Description("Distance"), TestMethod]
        public void TestDistanceMatrix()
        {
            {
                //Double (to test conversion between T and Double)
                Sparse<Double> s = DemoMatrix4();

                DumpMatrixes<Double>(s);

                DumpMatrixes<Double>(s);

                s.Distance(s, "test");

                DumpMatrixes<Double>(s);
                DumpInternals<Double>(s);
            }
            {
                //Int32 (to test conversion between T, Double and Int32)
                Sparse<Int32> s = DemoMatrix6();

                DumpMatrixes<Int32>(s);

                s.Distance(s, "test");

                DumpMatrixes<Int32>(s);
                DumpInternals<Int32>(s);
            }
        }

        [Owner("wvd_vegt"), Description("Dot"), TestMethod]
        public void TestDotMatrix()
        {
            //Double (to test conversion between T and Double)
            Sparse<Double> s1 = DemoMatrix4();
            Sparse<Double> s2 = DemoVector1();
            Sparse<Double> s = new Sparse<Double>();

            DumpMatrixes<Double>(s1);
            DumpMatrixes<Double>(s2);

            s.Dot(s1, s2, "TestDotMatrix");

            DumpMatrixes<Double>(s);
            DumpInternals<Double>(s);
        }

        [Owner("wvd_vegt"), Description("Frobenius"), TestMethod]
        public void TestFrobeniusMatrix()
        {
            //Double (to test conversion between T and Double)
            Sparse<Double> s1 = DemoMatrix4();
            Sparse<Double> s2 = DemoVector1();
            s2.Transpose();
            Sparse<Double> s = new Sparse<Double>();

            DumpMatrixes<Double>(s1);
            DumpMatrixes<Double>(s2);

            s.Frobenius(s1, s2, "TestFroneniusMatrix");

            DumpMatrixes<Double>(s);
            DumpInternals<Double>(s);
        }

        [Owner("wvd_vegt"), Description("Extract"), TestMethod]
        public void TestExtractMatrix()
        {
            //{
            //    //Double (to test conversion between T and Double)
            //    Sparse<Double> s = DemoMatrix1();

            //    DumpMatrixes<Double>(s);

            //    s.Extract(s, 2, 2, 4, 6);

            //    DumpMatrixes<Double>(s);
            //}
            {
                //Double (to test conversion between T and Double)
                Sparse<Double> s = DemoMatrix1();

                s.Reduce(2, 2, 4, 6);

                DumpMatrixes<Double>(s);
            }
        }

        [Owner("wvd_vegt"), Description("Multiply"), TestMethod]
        public void TestMultiplyMatrix()
        {
            Sparse<Int32> a = DemoMatrix8();
            Sparse<Int32> b = DemoMatrix9();

            Sparse<Int32> s = new Sparse<Int32>();

            s.Multiply(a, b, "TestMultiplyMatrix");

            DumpMatrixes<Int32>(a);
            DumpMatrixes<Int32>(b);
            DumpMatrixes<Int32>(s);
        }

        [Owner("wvd_vegt"), Description("Decompress"), TestMethod]
        public void TestDecompressMatrix()
        {
            Sparse<Int32> s = DemoMatrix8();

            s.Decompress();

            DumpMatrixes<Int32>(s);
            DumpInternals<Int32>(s);
        }

        [Owner("wvd_vegt"), Description("LoadHarwellBoeing"), TestMethod]
        public void TestLoadHBMatrix()
        {
            Sparse<Double> s = new Sparse<Double>();

            String FileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "HBInt32Matrix.hb");

            Console.WriteLine("Loading: " + FileName);
            s.LoadHarwellBoeing(FileName);

            //s.Transpose();

            DumpMatrixes<Double>(s);
            DumpInternals<Double>(s);
        }

        [Owner("wvd_vegt"), Description("LoadExcel"), TestMethod]
        public void TestLoadExcelMatrix()
        {
            Sparse<Double> s = new Sparse<Double>();

            String FileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "ExcelInt32Matrix.csv");

            Console.WriteLine("Loading: " + FileName);
            s.LoadExcel(FileName);

            //s.Transpose();

            DumpMatrixes<Double>(s);
            DumpInternals<Double>(s);
        }

        #region DemoData

        /// <summary>
        /// Full Demo Matrix
        /// </summary>
        /// <returns></returns>
        private static Sparse<Double> DemoMatrix1()
        {
            //| 11   0   0  14   0 |
            //|  0  22   0   0  25 |
            //|  0   0  33   0   0 |
            //| 41   0   0  44  45 |
            //| 51   0   0  54  55 |
            //Results in:
            //A(*)  = [11,14,22,25,33,41,44,45,51,54,55]       Stores the Values      , size = FNonZeroCount
            //JA(*) = [ 0, 3, 1, 4, 2, 0, 3, 4, 0, 3, 4]       Stores Column Indexes  , size = FNonZeroCount
            //IA(*) = [ 0,    2,    4, 5,       8,      11]    Stores Indexes into JA , size = RowCount

            const Int32 Size = 5;
            Sparse<Double> Result = new Sparse<Double>(Size, Size, 11, "DemoMatrix1");

            Result.AddElement(0, 0, 11);
            Result.AddElement(0, 3, 14);
            Result.AddElement(1, 1, 22);
            Result.AddElement(1, 4, 25);
            Result.AddElement(2, 2, 33);
            Result.AddElement(3, 0, 41);
            Result.AddElement(3, 3, 44);
            Result.AddElement(3, 4, 45);
            Result.AddElement(4, 0, 51);
            Result.AddElement(4, 3, 54);
            Result.AddElement(4, 4, 55);

            return Result;
        }

        /// <summary>
        /// No Value at 2,2
        /// </summary>
        /// <returns></returns>
        private static Sparse<Double> DemoMatrix2()
        {
            //| 11   0   0  14   0 |
            //|  0  22   0   0  25 |
            //|  0   0   0   0   0 |
            //| 41   0   0  44  45 |
            //| 51   0   0  54  55 |

            //Results in:

            //A(*)  = [11,14,22,25,41,44,45,51,54,55]       Stores the Values      , size = FNonZeroCount
            //JA(*) = [ 0, 3, 1, 4, 0, 3, 4, 0, 3, 4]       Stores column indexes  , size = FNonZeroCount
            //IA(*) = [ 0,    2,    4, 4,       7,      10] Stores indexes into ja , size = RowCount+1
            //                                          |
            //                                          NonZeroCount

            const Int32 Size = 5;
            Sparse<Double> Result = new Sparse<Double>(Size, Size, 10, "DemoMatrix2");

            Result.AddElement(0, 0, 11);
            Result.AddElement(0, 3, 14);
            Result.AddElement(1, 1, 22);
            Result.AddElement(1, 4, 25);
            //Result.AddElement(2, 2, 33);
            Result.AddElement(3, 0, 41);
            Result.AddElement(3, 3, 44);
            Result.AddElement(3, 4, 45);
            Result.AddElement(4, 0, 51);
            Result.AddElement(4, 3, 54);
            Result.AddElement(4, 4, 55);

            return Result;
        }

        /// <summary>
        /// Zero Value at 2,2
        /// </summary>
        /// <returns></returns>
        private static Sparse<Double> DemoMatrix3()
        {
            //| 11   0   0  14   0 |
            //|  0  22   0   0  25 |
            //|  0   0 0.0   0   0 |
            //| 41   0   0  44  45 |
            //| 51   0   0  54  55 |
            //Results in:
            //A(*)  = [11,14,22,25,0.0,41,44,45,51,54,55]      Stores the Values      , size = FNonZeroCount
            //JA(*) = [ 0, 3, 1, 4, 2, 0, 3, 4, 0, 3, 4]       Stores Column Indexes  , size = FNonZeroCount
            //IA(*) = [ 0,    2,    4, 5,       8,      11]    Stores Indexes into JA , size = RowCount

            const Int32 Size = 5;
            Sparse<Double> Result = new Sparse<Double>(Size, Size, 11, "DemoMatrix3");

            Result.AddElement(0, 0, 11);
            Result.AddElement(0, 3, 14);
            Result.AddElement(1, 1, 22);
            Result.AddElement(1, 4, 25);
            Result.AddElement(2, 2, default(Double)); //Add a Zero value...
            Result.AddElement(3, 0, 41);
            Result.AddElement(3, 3, 44);
            Result.AddElement(3, 4, 45);
            Result.AddElement(4, 0, 51);
            Result.AddElement(4, 3, 54);
            Result.AddElement(4, 4, 55);

            return Result;
        }

        /// <summary>
        /// Small (Diagonal) 2x2 Matrix
        /// </summary>
        /// <returns></returns>
        private static Sparse<Double> DemoMatrix4()
        {
            const Int32 Size = 2;
            Sparse<Double> Result = new Sparse<Double>(Size, Size, 2, "DemoMatrix4");

            Result.AddElement(0, 0, 11);
            Result.AddElement(1, 1, 25);

            return Result;
        }

        /// <summary>
        /// Diagonal Matrix
        /// </summary>
        /// <returns></returns>
        private static Sparse<Double> DemoMatrix5()
        {
            const Int32 Size = 10;
            Sparse<Double> Result = new Sparse<Double>(Size, Size, Size, "DemoMatrix5");
            for (Int32 i = 0; i < Size; i++)
            {
                Result.AddElement(i, i, 1.0 * i);
            }
            return Result;
        }

        /// <summary>
        /// Small 2x2 Matrix
        /// </summary>
        /// <returns></returns>
        private static Sparse<Int32> DemoMatrix6()
        {
            const Int32 Size = 2;
            Sparse<Int32> Result = new Sparse<Int32>(Size, Size, 2, "DemoMatrix6");

            Result.AddElement(0, 0, 11);
            Result.AddElement(1, 1, 25);

            return Result;
        }

        /// <summary>
        /// Matrix with Empty First Row.
        /// </summary>
        /// <returns></returns>
        private static Sparse<Int32> DemoMatrix7()
        {
            Sparse<Int32> Result = new Sparse<Int32>(4, 3, 5, "DemoMatrix7");

            //Result.AddElement(0, 0, 1);
            //Result.AddElement(0, 1, 3);
            //Result.AddElement(0, 2, 2);
            Result.AddElement(1, 1, 4);
            Result.AddElement(1, 2, -1);
            Result.AddElement(3, 0, 5);
            Result.AddElement(3, 1, -2);
            Result.AddElement(3, 2, 11);

            return Result;
        }

        /// <summary>
        /// Multiply Matrix 1.
        /// </summary>
        /// <returns></returns>
        private static Sparse<Int32> DemoMatrix8()
        {
            Sparse<Int32> Result = new Sparse<Int32>(2, 3, 5, "DemoMatrix8");

            Result.AddElement(0, 1, -1);
            Result.AddElement(0, 2, 2);

            Result.AddElement(1, 0, 4);
            Result.AddElement(1, 1, 11);
            Result.AddElement(1, 2, 2);

            return Result;
        }

        /// <summary>
        /// Multiply Matrix 2.
        /// </summary>
        /// <returns></returns>
        private static Sparse<Int32> DemoMatrix9()
        {
            Sparse<Int32> Result = new Sparse<Int32>(3, 2, 6, "DemoMatrix9");

            Result.AddElement(0, 0, 3);
            Result.AddElement(0, 1, -1);

            Result.AddElement(1, 0, 1);
            Result.AddElement(1, 1, 2);

            Result.AddElement(2, 0, 6);
            Result.AddElement(2, 1, 1);

            return Result;
        }

        /// <summary>
        /// Horizontal 2 Element Vector
        /// </summary>
        /// <returns></returns>
        private static Sparse<Double> DemoVector1()
        {
            const Int32 Size = 2;
            Sparse<Double> Result = new Sparse<Double>(1, Size, Size, "DemoVector1");
            for (Int32 i = 0; i < Size; i++)
            {
                Result.AddElement(0, i, 1.0 * (i + 2));
            }
            return Result;
        }

        #endregion DemoData

        #region DebugOutput

        private void DumpInternals<T>(Sparse<T> s)
        {
            Console.Write("RowPtr |");
            for (Int32 r = 0; r <= s.RowCount; r++)
            {
                Console.Write(" {0:00} |", s.RowPtr[r]);
            }
            Console.WriteLine("");

            Console.Write("ColNdx |");
            for (Int32 c = 0; c < s.NonZeroCount; c++)
            {
                Console.Write(" {0:00} |", s.ColNdx[c]);
            }
            Console.WriteLine("");

            Console.Write("Values |");
            for (Int32 c = 0; c < s.NonZeroCount; c++)
            {
                Console.Write(" {0} |", s.Values[c]);
            }
            Console.WriteLine("");
            Console.WriteLine("");
        }

        private void DumpMatrixes<T>(Sparse<T> s)
        {
            Int32 r = 0;
            Int32 c = 0;
            T v = default(T);

            if (s.First(ref r, ref c, ref v))
            {
                for (Int32 i = 0; i < s.RowCount; i++)
                {
                    String Result = String.Format("{0:#######0}>", i);

                    for (Int32 j = 0; j < s.ColCount; j++)
                    {
                        if ((i == r) && (j == c))
                        {
                            Result += String.Format(" | {0:00.000}", v);
                            s.Next(ref r, ref c, ref v);
                        }
                        else
                        {
                            Result += String.Format(" | {0:00.000}", default(T));
                        }
                    }
                    Result += " |";

                    Console.WriteLine(Result);
                }
                Console.WriteLine("{0} Columns", s.ColCount);
                Console.WriteLine("{0} Rows", s.RowCount);
                if (s.NonZeroCount == 1 && Number<T>.IsDefault(s.Values[0]))
                {
                    Console.WriteLine("{0} Zero Element Matrix", s.NonZeroCount);
                }
                else
                {
                    Console.WriteLine("{0} NonZero Element Matrix", s.NonZeroCount);
                }
                Console.WriteLine("Comment: '{0}'", s.Comment);
            }
            else
            {
                Console.WriteLine("{0} Columns", s.ColCount);
                Console.WriteLine("{0} Rows", s.RowCount);
                Console.WriteLine("Zero Element Matrix");
                Console.WriteLine("Comment: '{0}'", s.Comment);
            }
            Console.WriteLine("");
        }

        #endregion DebugOutput

        #endregion SparseMatrix
    
    }
}
